/**
 * www.easyplatform.cn ©2016
 */
package cn.easyplatform.studio.web.editors.project;

import cn.easyplatform.entities.BaseEntity;
import cn.easyplatform.entities.beans.task.TaskBean;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.studio.StudioApp;
import cn.easyplatform.studio.cmd.biz.BatchUpdateCmd;
import cn.easyplatform.studio.cmd.biz.UpdateCmd;
import cn.easyplatform.studio.cmd.entity.GetBaseEntityListCmd;
import cn.easyplatform.studio.cmd.entity.GetEntityCmd;
import cn.easyplatform.studio.cmd.entity.GetEntityListCmd;
import cn.easyplatform.studio.cmd.entity.QueryCmd;
import cn.easyplatform.studio.cmd.identity.GetAccessInfoCmd;
import cn.easyplatform.studio.cmd.identity.GetMenusCmd;
import cn.easyplatform.studio.context.Contexts;
import cn.easyplatform.studio.utils.WebUtils;
import cn.easyplatform.studio.vos.*;
import cn.easyplatform.studio.web.editors.AbstractPanelEditor;
import cn.easyplatform.studio.web.editors.BandboxCallback;
import cn.easyplatform.studio.web.layout.WorkbenchController;
import cn.easyplatform.studio.web.views.impl.AbstractView;
import cn.easyplatform.type.EntityType;
import cn.easyplatform.type.FieldType;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Components;
import org.zkoss.zk.ui.event.DropEvent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zul.*;

import java.util.*;

/**
 * @author <a href="mailto:shiny_vc@163.com">陈云亮</a> <br/>
 * @since 2.0.0 <br/>
 */
public class MenuEditor extends AbstractPanelEditor {

    private Tree menuTree;

    private Textbox key;

    private Textbox name;

    private Textbox desp;

    private Textbox parent;

    private Bandbox image;

    private Grid tasks;

    private Map<String, Treeitem> map;

    private MenuVo selectedMenu;

    private Textbox searchTextbox;

    private List<AccessVo> accessVos;

    public MenuEditor(WorkbenchController workbench, String id) {
        super(workbench, id);
    }

    @Override
    public void create(Object... args) {
        Idspace is = createPanel(Labels.getLabel("menu.menu"), "~./images/menu.gif", "~./include/editor/project/menu.zul");
        for (Component comp : is.getFellows()) {
            if (comp.getId().equals("projectMenu_tree_menuTree")) {
                menuTree = (Tree) comp;
                comp.addEventListener(Events.ON_SELECT, this);
            } else if (comp.getId().equals("projectMenu_textbox_id"))
                key = (Textbox) comp;
            else if (comp.getId().equals("projectMenu_textbox_name"))
                name = (Textbox) comp;
            else if (comp.getId().equals("projectMenu_textbox_desp"))
                desp = (Textbox) comp;
            else if (comp.getId().equals("projectMenu_textbox_parent"))
                parent = (Textbox) comp;
            else if (comp.getId().equals("projectMenu_bandbox_image")) {
                image = (Bandbox) comp;
                comp.addEventListener(Events.ON_OPEN, this);
            } else if (comp.getId().equals("projectMenu_grid_tasks")) {
                tasks = (Grid) comp;
                tasks.setDroppable(EntityType.TASK.getName());
                comp.addEventListener(Events.ON_DROP, this);
            } else if (comp instanceof Button) {
                String AuthorizedKey = null;
                if (comp.getId().equals("projectMenu_button_menuAdd"))
                    AuthorizedKey = "menuAdd";
                else if (comp.getId().equals("projectMenu_button_menuDelete"))
                    AuthorizedKey = "menuDelete";
                else if (comp.getId().equals("projectMenu_button_menuEdit"))
                    AuthorizedKey = "menuEdit";
                boolean isAuthorized = Contexts.getUser().isAuthorized(AuthorizedKey);
                if (isAuthorized)
                    comp.addEventListener(Events.ON_CLICK, this);
                else
                    ((Button) comp).setDisabled(true);
            } else if (comp.getId().equals("menu_textbox_search")) {
                searchTextbox = (Textbox) comp;
                searchTextbox.addEventListener(Events.ON_OK, this);
            }
        }
        accessVos = StudioApp.execute(new GetAccessInfoCmd());
        redraw(StudioApp.execute(new GetMenusCmd()));
        selectedMenu = new MenuVo();
        selectedMenu.setParentMenuId("");
        selectedMenu.setCode('C');
    }

    private void redraw(List<MenuVo> menus) {
        menuTree.getTreechildren().getChildren().clear();
        //menus = StudioApp.execute(new GetMenusCmd());
        map = new HashMap<String, Treeitem>();
        for (MenuVo menu : menus) {
            Treeitem parent = map.get(menu.getParentMenuId());
            if (parent == null) {
                parent = new Treeitem();
                parent.setValue(menu);
                Treerow row = new Treerow();
                Treecell cell = new Treecell(menu.getId());
                cell.setParent(row);
                cell = new Treecell(menu.getName());
                cell.setParent(row);
                cell = new Treecell(menu.getDesp());
                cell.setParent(row);
                row.setParent(parent);
                parent.setDraggable("d1");
                parent.setDroppable("d1");
                parent.addEventListener(Events.ON_DROP, this);
                parent.setParent(menuTree.getTreechildren());
                parent.setOpen(false);
                map.put(menu.getId(), parent);
            } else {
                Treeitem ti = new Treeitem();
                ti.setValue(menu);
                Treerow row = new Treerow();
                Treecell cell = new Treecell(menu.getId());
                cell.setParent(row);
                cell = new Treecell(menu.getName());
                cell.setParent(row);
                cell = new Treecell(menu.getDesp());
                cell.setParent(row);
                row.setParent(ti);
                Treechildren tc = parent.getTreechildren();
                if (tc == null) {
                    tc = new Treechildren();
                    tc.setParent(parent);
                }
                ti.setDraggable("d1");
                ti.setDroppable("d1");
                ti.addEventListener(Events.ON_DROP, this);
                ti.setParent(tc);
                map.put(menu.getId(), ti);
            }
        }
    }

    private void setValue() {
        key.setValue(selectedMenu.getId());
        name.setValue(selectedMenu.getName());
        desp.setValue(selectedMenu.getDesp());
        parent.setValue(selectedMenu.getParentMenuId());
        image.setValue(selectedMenu.getImage());
        if (!Strings.isBlank(selectedMenu.getTasks())) {
            QueryResultVo result = StudioApp.execute(new QueryCmd(
                    EntityType.TASK.getName(), "entityId", selectedMenu
                    .getTasks(), 0));
            List<String> idList = new ArrayList<>();
            for (EntityVo entityVo: result.getEntities()) {
                if (Strings.isBlank(entityVo.getId()) == false)
                    idList.add(entityVo.getId());
            }
            List<BaseEntity> taskList = StudioApp.execute(new GetBaseEntityListCmd(idList));
            redrawTasks(taskList);
        } else
            Components.removeAllChildren(tasks.getRows());
    }

    @Override
    public void dispatch(Event event) {
        if (event.getName().equals(Events.ON_OPEN)) {// actionbox
            AbstractView.createIconView(new BandboxCallback(this, image), "*", event.getTarget())
                    .doOverlapped();
        } else if (event.getName().equals(Events.ON_SELECT)) {
            Treeitem ti = menuTree.getSelectedItem();
            selectedMenu = ti.getValue();
            setValue();
            key.setReadonly(true);
        } else if (event.getName().equals(Events.ON_DROP)) {
            DropEvent de = (DropEvent) event;
            if (de.getDragged() instanceof Row) {// 功能
                if (selectedMenu == null)
                    return;
                Row source = (Row) de.getDragged();
                BaseEntity baseEntity = null;
                if (source.getValue() instanceof EntityVo) {
                    EntityVo vo = source.getValue();
                    baseEntity = StudioApp.execute(new GetEntityCmd(vo.getId()));
                }
                if (de.getTarget() instanceof Grid) {
                    if (source.getGrid() == tasks) {// 如果是自已在内面拖拉
                        source.detach();
                        tasks.getRows().appendChild(source);
                    } else {
                        tasks.getRows().appendChild(createRow(baseEntity));
                    }
                } else {// 目标是row
                    int pos = tasks.getRows().getChildren()
                            .indexOf(de.getTarget());
                    if (source.getGrid() == tasks) {// 如果是自已在内面拖拉
                        source.detach();
                        tasks.getRows().getChildren().add(pos, source);
                    } else {
                        tasks.getRows().getChildren().add(pos, createRow(baseEntity));
                    }
                }
            } else if (de.getDragged() instanceof Treeitem) {// 树
                Treeitem source = (Treeitem) de.getDragged();
                Treeitem target = (Treeitem) de.getTarget();
                int pos = target.getIndex();
                source.detach();
                if (source.getParent() != target.getParent()) {// 不同结点下
                    MenuVo sv = source.getValue();
                    MenuVo tv = target.getValue();
                    sv.setParentMenuId(tv.getParentMenuId());
                    List<FieldVo> params = new ArrayList<FieldVo>();
                    params.add(new FieldVo(FieldType.VARCHAR, sv
                            .getParentMenuId()));
                    params.add(new FieldVo(FieldType.VARCHAR, sv.getId()));
                    StudioApp
                            .execute(new UpdateCmd(
                                    "update sys_menu_info set parentMenuId=? where menuId=?",
                                    params));
                }
                target.getParent().getChildren().add(pos, source);
                String sql = "update sys_menu_info set orderNo=? where menuId=?";
                List<List<FieldVo>> params = new ArrayList<List<FieldVo>>();
                int index = 1;
                for (Component c : target.getParent().getChildren()) {
                    Treeitem item = (Treeitem) c;
                    MenuVo mv = item.getValue();
                    mv.setOrderNo(index);
                    List<FieldVo> param = new ArrayList<FieldVo>();
                    param.add(new FieldVo(FieldType.INT, index++));
                    param.add(new FieldVo(FieldType.VARCHAR, mv.getId()));
                    params.add(param);
                }
                StudioApp.execute(new BatchUpdateCmd(sql, params));
            } else if (de.getDragged() instanceof Listitem) {
                if (selectedMenu == null)
                    return;
                EntityVo vo = ((Listitem) de.getDragged()).getValue();
                BaseEntity baseEntity = StudioApp.execute(new GetEntityCmd(vo.getId()));
                if (de.getTarget() == tasks)
                    tasks.getRows().getChildren().add(createRow(baseEntity));
                else {
                    int pos = tasks.getRows().getChildren()
                            .indexOf(de.getTarget());
                    tasks.getRows().getChildren().add(pos, createRow(baseEntity));
                }
            }
        } else if (event.getTarget() instanceof A) {
            Component c = event.getTarget();
            c.getParent().detach();
        } else if (event.getTarget() instanceof Button) {
            Component c = event.getTarget();
            if (c.getId().equals("projectMenu_button_menuAdd")) {
                String parentId = "";
                if (selectedMenu != null)
                    parentId = selectedMenu.getId();
                selectedMenu = new MenuVo();
                selectedMenu.setParentMenuId(parentId);
                selectedMenu.setCode('C');
                setValue();
                key.setReadonly(false);
            } else if (c.getId().equals("projectMenu_button_menuDelete")) {
                if (selectedMenu == null || selectedMenu.getCode() == 'C') {
                    WebUtils.showError(Labels.getLabel("editor.select",
                            new String[]{Labels.getLabel("entity.page.menu")}));
                    return;
                }
                WebUtils.showConfirm(Labels.getLabel("button.delete"), this);
            } else if (c.getId().equals("projectMenu_button_menuEdit")) {//save
                if (selectedMenu == null) {
                    WebUtils.showError(Labels.getLabel("editor.select",
                            new String[]{Labels.getLabel("entity.page.menu")}));
                    return;
                }
                if (Strings.isBlank(key.getValue())) {
                    WebUtils.notEmpty(Labels.getLabel("entity.id"));
                    return;
                }
                if (Strings.isBlank(name.getValue())) {
                    WebUtils.notEmpty(Labels.getLabel("entity.name"));
                    return;
                }
                String parentId = selectedMenu.getParentMenuId();
                selectedMenu.setId(key.getValue());
                selectedMenu.setName(name.getValue());
                selectedMenu.setDesp(desp.getValue());
                selectedMenu.setParentMenuId(this.parent.getValue());
                selectedMenu.setImage(this.image.getValue());
                List<FieldVo> params = new ArrayList<FieldVo>();
                Component parent = null;
                if (Strings.isBlank(selectedMenu.getParentMenuId()))
                    parent = menuTree.getTreechildren();
                else {
                    Treeitem ti = map.get(selectedMenu.getParentMenuId());
                    if (ti == null)
                        parent = menuTree.getTreechildren();
                    else {
                        parent = ti.getTreechildren();
                        if (parent == null) {
                            parent = new Treechildren();
                            ti.appendChild(parent);
                        }
                    }
                }
                if (selectedMenu.getCode() == 'C')
                    selectedMenu.setOrderNo(parent.getChildren().size() + 1);
                if (!tasks.getRows().getChildren().isEmpty()) {
                    StringBuilder sb = new StringBuilder();
                    Iterator<Component> itr = tasks.getRows().getChildren()
                            .iterator();
                    while (itr.hasNext()) {
                        Row row = (Row) itr.next();
                        BaseEntity vo = row.getValue();
                        sb.append(vo.getId());
                        if (itr.hasNext())
                            sb.append(",");
                    }
                    selectedMenu.setTasks(sb.toString());
                } else
                    selectedMenu.setTasks("");
                params.add(new FieldVo(FieldType.VARCHAR, selectedMenu
                        .getName()));
                params.add(new FieldVo(FieldType.VARCHAR, selectedMenu
                        .getImage()));
                params.add(new FieldVo(FieldType.INT, selectedMenu.getOrderNo()));
                params.add(new FieldVo(FieldType.VARCHAR, selectedMenu
                        .getParentMenuId()));
                params.add(new FieldVo(FieldType.VARCHAR, selectedMenu
                        .getTasks()));
                params.add(new FieldVo(FieldType.VARCHAR, selectedMenu
                        .getDesp()));
                if (selectedMenu.getCode() == 'C') {
                    params.add(
                            0,
                            new FieldVo(FieldType.VARCHAR, selectedMenu.getId()));
                    if (StudioApp
                            .execute(
                                    event.getTarget(),
                                    new UpdateCmd(
                                            "insert into sys_menu_info (menuId,name,image,orderNo,parentMenuId,tasks,desp) values (?,?,?,?,?,?,?)",
                                            params))) {
                        Treeitem ti = new Treeitem();
                        ti.setValue(selectedMenu);
                        Treerow row = new Treerow();
                        Treecell cell = new Treecell(selectedMenu.getId());
                        cell.setParent(row);
                        cell = new Treecell(selectedMenu.getName());
                        cell.setParent(row);
                        cell = new Treecell(selectedMenu.getDesp());
                        cell.setParent(row);
                        row.setParent(ti);
                        ti.setDraggable("d1");
                        ti.setDroppable("d1");
                        ti.addEventListener(Events.ON_DROP, this);
                        ti.setParent(parent);
                        map.put(selectedMenu.getId(), ti);
                        ti.setSelected(true);
                        selectedMenu.setCode('U');
                        WebUtils.showSuccess(Labels.getLabel("button.save")
                                + Labels.getLabel("entity.page.menu")
                                + selectedMenu.getId());
                    }
                } else {
                    params.add(new FieldVo(FieldType.VARCHAR, selectedMenu
                            .getId()));
                    if (StudioApp
                            .execute(
                                    event.getTarget(),
                                    new UpdateCmd(
                                            "update sys_menu_info set name=?,image=?,orderNo=?,parentMenuId=?,tasks=?,desp=? where menuId=?",
                                            params))) {
                        Treeitem ti = map.get(selectedMenu.getId());
                        if (!Lang.equals(parentId,
                                selectedMenu.getParentMenuId())) {// 已更换父菜单
                            ti.detach();
                            parent.appendChild(ti);
                        }
                        List<Treecell> comps = ti.getTreerow().getChildren();
                        comps.get(0).setLabel(selectedMenu.getId());
                        comps.get(1).setLabel(selectedMenu.getName());
                        comps.get(2).setLabel(selectedMenu.getDesp());
                        WebUtils.showSuccess(Labels.getLabel("button.save")
                                + Labels.getLabel("entity.page.menu")
                                + selectedMenu.getId());
                    }
                }
            }
        } else if (event.getTarget().equals(searchTextbox)) {
            if (event instanceof OpenEvent) {
                OpenEvent evt = (OpenEvent) event;
                String val = (String) evt.getValue();
                ((Textbox) event.getTarget()).setValue(val);
            }
            search();
        } else if (event.getName().equals(Events.ON_OK)) {
            List<FieldVo> params = new ArrayList<FieldVo>();
            params.add(new FieldVo(FieldType.VARCHAR, selectedMenu.getId()));
            if (StudioApp.execute(new UpdateCmd(
                    "delete from sys_menu_info where menuId=?", params))) {
                map.remove(selectedMenu.getId()).detach();
                selectedMenu = new MenuVo();
                selectedMenu.setParentMenuId("");
                selectedMenu.setCode('C');
                setValue();
                key.setReadonly(false);
            }
        }
    }

    private void redrawTasks(List<BaseEntity> data) {
        Components.removeAllChildren(tasks.getRows());
        String[] tmp = selectedMenu.getTasks().split(",");
        if (data != null && data.size() > 0) {
            for (String taskId : tmp) {
                Iterator<BaseEntity> itr = data.iterator();
                while (itr.hasNext()) {
                    BaseEntity vo = itr.next();
                    if (taskId.equals(vo.getId())) {
                        tasks.getRows().appendChild(createRow(vo));
                        itr.remove();
                        break;
                    }
                }
            }
        }
    }

    private Row createRow(BaseEntity vo) {
        Row row = new Row();
        row.setValue(vo);
        row.appendChild(new Label(vo.getId()));
        row.appendChild(new Label(vo.getName()));
        row.appendChild(new Label(vo.getDescription()));
        Div accessDiv = new Div();
        accessDiv.setStyle("display: flex;flex-direction: row;flex-wrap: wrap;min-width:10px;justify-content: center;");
        String accessString = ((TaskBean) vo).getAccess();
        if (Strings.isBlank(accessString) == false) {
            List<String> accessList = Arrays.asList(accessString.split(","));
            if (accessList != null && accessList.size() > 0) {
                for (String accessCode: accessList) {
                    String popContent = null;
                    for (AccessVo accessVo: accessVos) {
                        StringBuffer codeString = new StringBuffer(accessVo.getCode());
                        if (Strings.isBlank(accessVo.getControlType()) == false)
                            codeString.append("_").append(accessVo.getControlType());
                        if (accessCode.equals(codeString.toString())) {
                            popContent = accessVo.getName();
                            break;
                        }
                    }
                    Div labelDiv = new Div();
                    labelDiv.setStyle("padding-left: 8px;padding-right: 8px;");
                    labelDiv.setSclass("ui-div-center-parent");
                    labelDiv.setTooltip(accessCode + ", position=after_start, delay=300");
                    Label showLabel = new Label(accessCode);
                    labelDiv.appendChild(showLabel);
                    accessDiv.appendChild(labelDiv);

                    Popup popup = new Popup();
                    popup.setId(accessCode);
                    Label popupLabel = new Label(popContent);
                    popup.appendChild(popupLabel);
                    accessDiv.appendChild(popup);
                }
            }
        }
        row.appendChild(accessDiv);
        row.setDraggable(EntityType.TASK.getName());
        row.setDroppable(EntityType.TASK.getName());
        row.addEventListener(Events.ON_DROP, this);
        A del = new A();
        del.setIconSclass("z-icon-times");
        del.addEventListener(Events.ON_CLICK, this);
        row.appendChild(del);
        return row;
    }

    private void search() {
        List<MenuVo> menuVos = StudioApp.execute(new GetMenusCmd());
        List<MenuVo> searchVos = new ArrayList<>();
        if (Strings.isBlank(searchTextbox.getValue().trim()) == false) {
            for (MenuVo menuVo : menuVos) {
                if (Strings.isBlank(menuVo.getParentMenuId())) {
                    if (menuVo.getId().contains(searchTextbox.getValue().trim())) {
                        searchVos.add(menuVo);
                        continue;
                    } else if (menuVo.getName().contains(searchTextbox.getValue().trim())) {
                        searchVos.add(menuVo);
                        continue;
                    }
                } else {
                    searchVos.add(menuVo);
                }
            }
            redraw(searchVos);
        } else {
            redraw(menuVos);
        }
    }
}
